/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.camachosanchez.reportes;

import com.camachosanchez.bean.ComprobacionBandaRodamientoPresion;
import com.camachosanchez.bean.ConfiguracionBajaNeumatico;
import com.camachosanchez.bean.EstadosMedicion;
import com.camachosanchez.bean.Flotillas;
import com.camachosanchez.bean.MedicionComprobacion;
import com.camachosanchez.bean.TiposEje;
import com.camachosanchez.bean.TiposVehiculo;
import com.camachosanchez.gui.Principal;
import com.camachosanchez.util.JPAUtil;
import com.camachosanchez.util.ReportUtil;
import com.camachosanchez.util.SQLUtil;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Point;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Formatter;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.swing.JOptionPane;

/**
 *
 * @author ZULLY
 */
public class ReporteBajaNeumaticos {

    private EntityManagerFactory emf;
    private EntityManager em;
    private Formatter fmt;

    public ReporteBajaNeumaticos() {
        emf = JPAUtil.getEntityManagerFactory();
        em = emf.createEntityManager();
        fmt = new Formatter();
    }

    public void generarReporte(Date fechaIni, Date fechaFin, Flotillas razonSocial, TiposEje tipoEje, TiposVehiculo tipoUnidad) {
        Document document = new Document(PageSize.A4.rotate(), 30, 30, 20, 20);
        try {
            Point p = SQLUtil.numeroEjes(tipoEje.getId());
//            int nroEjes = p.x;
            int nroNeumaticos = p.y;//más las dos de repuesto
            final Calendar cIni = Calendar.getInstance();
            cIni.setTime(fechaIni);
            final Calendar cFin = Calendar.getInstance();
            cFin.setTime(fechaIni);
            int anio = cIni.get(Calendar.YEAR);
            int mes = cIni.get(Calendar.MONTH);
            String[] nombreMes = {"Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio",
                "Agosto", "Setiembre", "Octubre", "Noviembre", "Diciembre"};
            String nombrePdf = "reportes/desmontajes_" + fmt.format("%02d", mes) + "-" + anio + ".pdf";
            PdfWriter.getInstance(document, new FileOutputStream(nombrePdf));
            document.open();

            PdfPTable tablaC = new PdfPTable(1);
            tablaC.setHorizontalAlignment(Element.ALIGN_CENTER);
            tablaC.setWidthPercentage(100);
            PdfPCell celda = new PdfPCell(new Phrase(("PRÓXIMOS DESMONTAJES EN " + nombreMes[mes] + " DEL " + anio).toUpperCase(), FontFactory.getFont(BaseFont.HELVETICA, 12, Font.NORMAL, BaseColor.BLACK)));
            celda.setHorizontalAlignment(Element.ALIGN_CENTER);
            celda.setBorder(Rectangle.NO_BORDER);
            tablaC.addCell(celda);
            document.add(tablaC);

            float[] anchoColsInf = {1f, 4f, 1.2f, 1.3f, 0.6f, 1.9f};
            PdfPTable tablaInf = new PdfPTable(anchoColsInf);
            tablaInf.setHorizontalAlignment(Element.ALIGN_CENTER);
            tablaInf.setSpacingBefore(10f);
            tablaInf.setWidthPercentage(100);
            tablaInf.addCell(ReportUtil.getCeldaBorde("RAZÓN SOCIAL:", 1, 1, BaseColor.WHITE, 0, 0, 9, 1));
            tablaInf.addCell(ReportUtil.getCeldaBorde(razonSocial.getNombre(), 1, 1, BaseColor.WHITE, 0, 0, 9, 0));
            tablaInf.addCell(ReportUtil.getCeldaBorde("TIPO DE UNIDAD:", 1, 1, BaseColor.WHITE, 0, 0, 9, 1));
            tablaInf.addCell(ReportUtil.getCeldaBorde(tipoUnidad.getNombre(), 1, 1, BaseColor.WHITE, 0, 0, 9, 0));
            tablaInf.addCell(ReportUtil.getCeldaBorde("MODELO:", 1, 1, BaseColor.WHITE, 0, 0, 9, 1));
            tablaInf.addCell(ReportUtil.getCeldaBorde(tipoEje.getNombre(), 1, 1, BaseColor.WHITE, 0, 0, 9, 0));
            document.add(tablaInf);

            float[] anchoCols = new float[nroNeumaticos + 1 + 2];//+2 neumáticos de repuesto
            anchoCols[0] = 2f;
            for (int i = 1; i < anchoCols.length; i++) {
                anchoCols[i] = 1.5f;
            }

            PdfPTable tablaVehiculos = new PdfPTable(anchoCols);
            tablaVehiculos.setWidthPercentage(100);
            tablaVehiculos.setSpacingBefore(20f);
//
            tablaVehiculos.addCell(ReportUtil.getCelda("VEHÍCULO", 1, 2, BaseColor.WHITE, 1, 0.5f, 11, 1));
            tablaVehiculos.addCell(ReportUtil.getCelda("POSICIÓN", nroNeumaticos + 2, 1, BaseColor.WHITE, 1, 0.5f, 11, 1));
            for (int i = 1; i <= nroNeumaticos; i++) {
                tablaVehiculos.addCell(ReportUtil.getCelda("" + i, 1, 1, BaseColor.WHITE, 1, 0.5f, 10, 1));
            }
//            //Neumáticos de Repuesto
            tablaVehiculos.addCell(ReportUtil.getCelda("R1", 1, 1, BaseColor.WHITE, 1, 0.5f, 10, 1));
            tablaVehiculos.addCell(ReportUtil.getCelda("R2", 1, 1, BaseColor.WHITE, 1, 0.5f, 10, 1));
//
            List<ConfiguracionBajaNeumatico> parametros = getParametrosColores();
            int totalVehiculos = 0, totalNeumaticos = 0;
            String placa = "";
            List<ComprobacionBandaRodamientoPresion> datos = this.getDatos(fechaIni, fechaFin, razonSocial.getId(), tipoEje);
            for (ComprobacionBandaRodamientoPresion item : datos) {
                if (placa.compareTo(item.getIdVehiculo().getPlaca()) != 0) {
                    totalVehiculos++;
                }
                List<MedicionComprobacion> detalle = OrdenarXPosicion(item.getMedicionComprobacionList());
                detalle = completarNeumaticos(detalle, nroNeumaticos + 2);
                tablaVehiculos.addCell(ReportUtil.getCelda(item.getIdVehiculo().getPlaca(), 1, 1, BaseColor.WHITE, 0, 0.5f, 10, 1));
                for (MedicionComprobacion neumaticoMedido : detalle) {
                    if (neumaticoMedido != null) {
                        totalNeumaticos++;
                        BaseColor color = getColorXParametros(parametros, neumaticoMedido);
                        tablaVehiculos.addCell(getTablaNeumatico(neumaticoMedido, color));
                    } else {
                        tablaVehiculos.addCell(ReportUtil.getCelda("", 1, 1, BaseColor.WHITE, 1, 0.5f, 10, 0));
                    }
                }
                placa = item.getIdVehiculo().getPlaca();
            }
            document.add(tablaVehiculos);

            float[] anchoColsEstadistica = {3f, 1f};//version prueba
            PdfPTable tablaEstadistica = new PdfPTable(anchoColsEstadistica);
            tablaEstadistica.setHorizontalAlignment(Element.ALIGN_LEFT);
            tablaEstadistica.setSpacingBefore(20);
            tablaEstadistica.setWidthPercentage(40);

            tablaEstadistica.addCell(ReportUtil.getCelda("ESTADÍSTICA", 2, 1, BaseColor.WHITE, 1, 0.5f, 10, 1));
            tablaEstadistica.addCell(ReportUtil.getCelda("TOTAL DE VEHÍCULOS", 1, 1, BaseColor.WHITE, 0, 0.5f, 10, 0));
            tablaEstadistica.addCell(ReportUtil.getCelda("" + totalVehiculos, 1, 1, BaseColor.WHITE, 2, 0.5f, 10, 1));
            tablaEstadistica.addCell(ReportUtil.getCelda("TOTAL DE NEUMÁTICOS", 1, 1, BaseColor.WHITE, 0, 0.5f, 10, 0));
            tablaEstadistica.addCell(ReportUtil.getCelda("" + totalNeumaticos, 1, 1, BaseColor.WHITE, 2, 0.5f, 10, 1));

            document.add(tablaEstadistica);

            float[] anchoColsLeyenda = {3f, 1f, 1f, 0.8f, 0.5f};//version prueba
            PdfPTable tablaLeyenda = new PdfPTable(anchoColsLeyenda);
            tablaLeyenda.setHorizontalAlignment(Element.ALIGN_LEFT);
            tablaLeyenda.setSpacingBefore(20);
            tablaLeyenda.setWidthPercentage(40);

            tablaLeyenda.addCell(ReportUtil.getCelda("DESCRIPCIÓN", 1, 1, BaseColor.WHITE, 1, 0.5f, 10, 1));
            tablaLeyenda.addCell(ReportUtil.getCelda("VI", 1, 1, BaseColor.WHITE, 1, 0.5f, 10, 1));
            tablaLeyenda.addCell(ReportUtil.getCelda("VF", 1, 1, BaseColor.WHITE, 1, 0.5f, 10, 1));
            tablaLeyenda.addCell(ReportUtil.getCelda("COLOR", 1, 1, BaseColor.WHITE, 1, 0.5f, 10, 1));
            tablaLeyenda.addCell(ReportUtil.getCelda("R", 1, 1, BaseColor.WHITE, 1, 0.5f, 10, 1));

            for (ConfiguracionBajaNeumatico item : parametros) {
                Color c = new Color(item.getColor());
                tablaLeyenda.addCell(ReportUtil.getCelda(item.getDescripcion(), 1, 1, BaseColor.WHITE, 0, 0.5f, 10, 0));
                tablaLeyenda.addCell(ReportUtil.getCelda("" + item.getValorInicial(), 1, 1, BaseColor.WHITE, 1, 0.5f, 10, 0));
                tablaLeyenda.addCell(ReportUtil.getCelda("" + item.getValorFinal(), 1, 1, BaseColor.WHITE, 1, 0.5f, 10, 0));
                tablaLeyenda.addCell(ReportUtil.getCelda("", 1, 1, new BaseColor(c.getRed(), c.getGreen(), c.getBlue()), 0, 0.5f, 10, 0));
                String nroR = ((item.getNroReencauches() == null) ? "" : item.getNroReencauches() + "");
                tablaLeyenda.addCell(ReportUtil.getCelda(nroR, 1, 1, BaseColor.WHITE, 1, 0.5f, 10, 0));
            }
            document.add(tablaLeyenda);
            document.close();
            File pdfFile = new File(nombrePdf);
            if (Desktop.isDesktopSupported()) {
                Desktop.getDesktop().open(pdfFile);
            } else {
                JOptionPane.showMessageDialog(null, "No se puede abrir el reporte.", "Error al abrir el archivo", JOptionPane.ERROR_MESSAGE);
            }
//            File pdfFile = new File(nombrePdf);
//            GUIUtil.abrirDialogoImpresion(pdfFile.getAbsolutePath());

        } catch (Exception ex) {
            JOptionPane.showMessageDialog(Principal.getInstance(), ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    private BaseColor getColorXParametros(List<ConfiguracionBajaNeumatico> parametros, MedicionComprobacion medicion) {
        BaseColor color = new BaseColor(255, 255, 255);
        double medicionMenor = medicion.getAlturaIzquierda();
        if (medicion.getAlturaCentro() < medicionMenor) {
            medicionMenor = medicion.getAlturaCentro();
        } else if (medicion.getAlturaDerecha() < medicionMenor) {
            medicionMenor = medicion.getAlturaDerecha();
        }
        ConfiguracionBajaNeumatico parametro = null;
        double vi, vf;
        int nroR;
        EstadosMedicion estado;
        for (ConfiguracionBajaNeumatico item : parametros) {
            vi = item.getValorInicial().doubleValue();
            vf = item.getValorFinal().doubleValue();
            
            if (item.getNroReencauches() != null && item.getIdEstadoMedicion() != null) {
                nroR = item.getNroReencauches();
                estado = item.getIdEstadoMedicion();
                if ((medicionMenor >= vi && medicionMenor <= vf && nroR == medicion.getNroReencauches() && estado.equals(medicion.getIdEstado()))) {
                    parametro = item;
                }
            } else if (item.getNroReencauches() != null && item.getIdEstadoMedicion() == null) {
                nroR = item.getNroReencauches();
                if ((medicionMenor >= vi && medicionMenor <= vf && nroR == medicion.getNroReencauches())) {
                    parametro = item;
                }
            } else if (item.getNroReencauches() == null && item.getIdEstadoMedicion() != null) {
                estado = item.getIdEstadoMedicion();
                if ((medicionMenor >= vi && medicionMenor <= vf && estado.equals(medicion.getIdEstado()))) {
                    parametro = item;
                }
            } else {
                if ((medicionMenor >= vi && medicionMenor <= vf)) {
                    parametro = item;
                }
            }
        }
        if (parametro != null) {
            Color c = new Color(parametro.getColor());
            color = new BaseColor(c.getRed(), c.getGreen(), c.getBlue());
        }
        return color;
    }

    private PdfPTable getTablaNeumatico(MedicionComprobacion medicion, BaseColor color) {
        float[] anchoCols = {0.5f, 1.5f, 1.5f};
        PdfPTable tabla = new PdfPTable(anchoCols);

        double medicionMenor = medicion.getAlturaIzquierda();
        if (medicion.getAlturaCentro() < medicionMenor) {
            medicionMenor = medicion.getAlturaCentro();
        } else if (medicion.getAlturaDerecha() < medicionMenor) {
            medicionMenor = medicion.getAlturaDerecha();
        }
        tabla.addCell(ReportUtil.getCelda("" + medicion.getNroReencauches(), 1, 1, color, 1, 0.5f, 10, 0));
        tabla.addCell(ReportUtil.getCelda(medicion.getIdNeumatico().getIdMarca().getIniciales(), 1, 1, color, 1, 0.5f, 10, 0));
        //tabla.addCell(ReportUtil.getCelda("" + medicion.getIdNeumatico().getId(),1,1,BaseColor.WHITE,1,0.5f,10,0));
        tabla.addCell(ReportUtil.getCelda("" + medicionMenor, 1, 1, color, 2, 0.5f, 10, 0));
        tabla.addCell(ReportUtil.getCelda(medicion.getIdNeumatico().getIdModelo().getMedida(), 3, 1, color, 1, 0.5f, 10, 0));
        return tabla;
    }

    private List<ComprobacionBandaRodamientoPresion> getDatos(Date fechaIni, Date fechaFin, int idRazonSocial, TiposEje tipoEje) {
        java.sql.Date sqlFechaIni = new java.sql.Date(fechaIni.getTime());
        java.sql.Date sqlFechaFin = new java.sql.Date(fechaFin.getTime());
        Query q1 = em.createQuery("SELECT C FROM ComprobacionBandaRodamientoPresion C "
                + "WHERE C.fechaEjecucion <= :fechaFin AND C.fechaEjecucion >= :fechaIni AND C.anulado = :anulado "
                + "AND C.idVehiculo.idFlotilla.id = :idFlotilla AND C.idVehiculo.idTipoEje.id = :idTipoEje "
                + "ORDER BY C.idVehiculo.placa, C.fechaEjecucion");
        q1.setParameter("fechaIni", sqlFechaIni);
        q1.setParameter("fechaFin", sqlFechaFin);
        q1.setParameter("anulado", false);
        q1.setParameter("idFlotilla", idRazonSocial);
        q1.setParameter("idTipoEje", tipoEje.getId());
        List<ComprobacionBandaRodamientoPresion> lista = this.quitarMedicionesRepetidas(q1.getResultList());
        return lista;
    }

    private List<ConfiguracionBajaNeumatico> getParametrosColores() {
        List<ConfiguracionBajaNeumatico> parametros = null;
        try {
            Query q = JPAUtil.getEntityManagerFactory().createEntityManager().createNamedQuery("ConfiguracionBajaNeumatico.findByEstado");
            q.setParameter("estado", true);//lista los activos
            parametros = q.getResultList();
        } catch (Exception e) {
            JOptionPane.showMessageDialog(Principal.getInstance(), e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
        } finally {
            return parametros;
        }
    }

    private List<MedicionComprobacion> OrdenarXPosicion(List<MedicionComprobacion> lista) {
        int tamanio = lista.size();
        MedicionComprobacion aux;
        for (int i = 1; i < tamanio; i++) {
            for (int j = 0; j < tamanio - i; j++) {
                if (lista.get(j).getPosicion() > lista.get(j + 1).getPosicion()) {
                    aux = lista.get(j);
                    lista.set(j, lista.get(j + 1));
                    lista.set(j + 1, aux);
                }
            }
        }
        MedicionComprobacion nR1 = null, nR2 = null;
        if (lista.get(0).getPosicion() == -1) {//si es el segundo neumático de repuesto
            nR2 = lista.get(0);
        } else if (lista.get(0).getPosicion() == 0) {
            nR1 = lista.get(0);
        }
        if (lista.get(1).getPosicion() == 0) {//si es el primer neumático de repuesto
            nR1 = lista.get(1);
        }
        if (nR1 != null) {
            lista.remove(nR1);
        }
        if (nR2 != null) {
            lista.remove(nR2);
        }
        lista.add(nR1);
        lista.add(nR2);
        return lista;
    }
    
    private List<MedicionComprobacion> completarNeumaticos(List<MedicionComprobacion> lista, int nroNeumaticos){
        List<MedicionComprobacion> listaCompleta = new ArrayList<MedicionComprobacion>();
        int pos;
        int j=0;
        for(int i=0; i<nroNeumaticos; i++){
            pos = i + 1;
            MedicionComprobacion medicion = null;
            if(j < lista.size()){
                medicion = lista.get(j);
            }
            if(medicion != null && ((medicion.getPosicion() > 0 && medicion.getPosicion() == pos) || medicion.getPosicion() <= 0)) {
                listaCompleta.add(medicion);
                j++;
            }else {
                listaCompleta.add(null);
            }
        }
        return listaCompleta;
    }
    
    private List<ComprobacionBandaRodamientoPresion> quitarMedicionesRepetidas(List<ComprobacionBandaRodamientoPresion> lista){
        List<ComprobacionBandaRodamientoPresion> listaCompleta = new ArrayList<ComprobacionBandaRodamientoPresion>();
        int pos;
        for(ComprobacionBandaRodamientoPresion item : lista){
            pos = buscar(listaCompleta, item);
            if(pos >= 0){
                listaCompleta.set(pos, item);
            } else if(pos == -1){
                listaCompleta.add(item);
            }
        }
        return listaCompleta;
    }
    
    private int buscar(List<ComprobacionBandaRodamientoPresion> lista, ComprobacionBandaRodamientoPresion medicion){
        int posicion = -1;
        int pos = 0;
        for(ComprobacionBandaRodamientoPresion item : lista){
            if(item.getIdVehiculo().getId().equals(medicion.getIdVehiculo().getId()) && 
                    ((!item.getFechaEjecucion().equals(medicion.getFechaEjecucion()) && medicion.getFechaEjecucion().after(item.getFechaEjecucion())) || 
                    (item.getFechaEjecucion().equals(medicion.getFechaEjecucion()) && medicion.getFechaInsercionActualizacion().after(item.getFechaInsercionActualizacion())))){
                posicion = pos;
            } else if(item.getIdVehiculo().getId().equals(medicion.getIdVehiculo().getId())){
                posicion = -2;
            }
            pos++;
        }
        return posicion;
    }
}
